"""
WVP-Pro API客户端
"""
import httpx
import asyncio
from typing import List, Dict, Optional, Any
from datetime import datetime
from core.config import settings
import structlog

logger = structlog.get_logger(__name__)


class WVPProDevice:
    """WVP-Pro设备信息"""
    def __init__(self, data: Dict[str, Any]):
        self.device_id = data.get('deviceId', '')
        self.name = data.get('name', '')
        self.manufacturer = data.get('manufacturer', '')
        self.model = data.get('model', '')
        self.firmware = data.get('firmware', '')
        self.transport = data.get('transport', '')
        self.ip = data.get('ip', '')
        self.port = data.get('port', 0)
        self.host_address = data.get('hostAddress', '')
        self.expires = data.get('expires', 0)
        self.register_time = data.get('registerTime', '')
        self.keepalive_time = data.get('keepaliveTime', '')
        self.channel_count = data.get('channelCount', 0)
        # WVP使用1表示在线，0表示离线
        self.online = data.get('online', 0) == 1
        self.charset = data.get('charset', '')
        self.channels = data.get('channels', [])


class WVPProChannel:
    """WVP-Pro通道信息"""
    def __init__(self, data: Dict[str, Any]):
        self.device_id = data.get('deviceId', '')
        self.channel_id = data.get('channelId', '')
        self.name = data.get('name', '')
        self.manufacture = data.get('manufacture', '')
        self.model = data.get('model', '')
        self.owner = data.get('owner', '')
        self.civil_code = data.get('civilCode', '')
        self.address = data.get('address', '')
        self.parental = data.get('parental', 0)
        self.parent_id = data.get('parentId', '')
        self.safety_way = data.get('safetyWay', 0)
        self.register_way = data.get('registerWay', 0)
        self.cert_num = data.get('certNum', '')
        self.certifiable = data.get('certifiable', 0)
        self.err_code = data.get('errCode', 0)
        self.end_time = data.get('endTime', '')
        self.secrecy = data.get('secrecy', '')
        self.ip_address = data.get('ipAddress', '')
        self.port = data.get('port', 0)
        self.password = data.get('password', '')
        self.ptz_type = data.get('PTZType', 0)  # 注意大小写
        self.status = data.get('status', 0)
        self.longitude = data.get('longitude', 0.0)
        self.latitude = data.get('latitude', 0.0)
        self.has_audio = data.get('hasAudio', False)


class WVPProStreamInfo:
    """WVP-Pro流信息"""
    def __init__(self, data: Dict[str, Any]):
        self.app = data.get('app', '')
        self.stream = data.get('stream', '')
        self.device_id = data.get('deviceId', '')
        self.channel_id = data.get('channelId', '')
        self.flv = data.get('flv', '')
        self.ws_flv = data.get('ws_flv', '')
        self.rtmp = data.get('rtmp', '')
        self.rtsp = data.get('rtsp', '')
        self.hls = data.get('hls', '')
        self.ts = data.get('ts', '')
        self.fmp4 = data.get('fmp4', '')
        self.ws_fmp4 = data.get('ws_fmp4', '')
        self.webrtc = data.get('webrtc', '')


class WVPProClient:
    """WVP-Pro API客户端"""
    
    def __init__(self, base_url: str = None, api_key: str = None, timeout: float = 30.0):
        self.base_url = base_url or settings.WVP_PRO_BASE_URL
        self.api_key = api_key or settings.WVP_PRO_API_KEY
        self.timeout = httpx.Timeout(timeout)
        self._client: Optional[httpx.AsyncClient] = None
        
        # 确保base_url以/结尾
        if not self.base_url.endswith('/'):
            self.base_url += '/'
    
    async def __aenter__(self):
        """异步上下文管理器入口"""
        await self._ensure_client()
        return self
    
    async def __aexit__(self, exc_type, exc_val, exc_tb):
        """异步上下文管理器出口"""
        await self.close()
    
    async def _ensure_client(self):
        """确保HTTP客户端已初始化"""
        if self._client is None:
            headers = {}
            if self.api_key:
                headers['Authorization'] = f'Bearer {self.api_key}'
            
            self._client = httpx.AsyncClient(
                base_url=self.base_url,
                headers=headers,
                timeout=self.timeout,
                follow_redirects=True
            )
    
    async def close(self):
        """关闭HTTP客户端"""
        if self._client:
            await self._client.aclose()
            self._client = None
    
    async def _ensure_authenticated(self):
        """确保已认证"""
        # 简单的认证检查 - 尝试登录
        login_result = await self.login()
        if not login_result:
            raise Exception("WVP-Pro认证失败")
    
    async def _request(self, method: str, endpoint: str, **kwargs) -> Dict[str, Any]:
        """发送HTTP请求"""
        await self._ensure_client()
        
        try:
            url = endpoint.lstrip('/')
            response = await self._client.request(method, url, **kwargs)
            response.raise_for_status()
            
            # 尝试解析JSON响应
            try:
                return response.json()
            except Exception:
                return {"data": response.text}
                
        except httpx.HTTPStatusError as e:
            logger.error(
                "WVP-Pro API请求失败",
                method=method,
                endpoint=endpoint,
                status_code=e.response.status_code,
                response_text=e.response.text
            )
            raise
        except Exception as e:
            logger.error(
                "WVP-Pro API请求异常",
                method=method,
                endpoint=endpoint,
                error=str(e)
            )
            raise
    
    async def get_device_list(self, page: int = 1, count: int = 100) -> List[WVPProDevice]:
        """获取设备列表"""
        try:
            # 确保已认证
            await self._ensure_authenticated()
            
            params = {
                'page': page,
                'count': count
            }
            
            # 使用正确的WVP API端点
            response = await self._request('GET', 'api/device/query/devices', params=params)
            
            devices = []
            # WVP返回格式: {"list": [...], "total": n}
            if 'list' in response:
                device_list = response['list']
                for device_data in device_list:
                    devices.append(WVPProDevice(device_data))
            elif isinstance(response, list):
                # 有些WVP版本直接返回数组
                for device_data in response:
                    devices.append(WVPProDevice(device_data))
            
            logger.info(f"获取到{len(devices)}个WVP-Pro设备")
            return devices
            
        except Exception as e:
            logger.error("获取WVP-Pro设备列表失败", exc_info=e)
            return []
    
    async def get_device_info(self, device_id: str) -> Optional[WVPProDevice]:
        """获取设备详情"""
        try:
            # 确保已登录
            if not await self.login():
                raise Exception("登录失败")
            
            response = await self._request('GET', f'api/device/query/{device_id}')
            
            if 'data' in response:
                return WVPProDevice(response['data'])
            
            return None
            
        except Exception as e:
            logger.error(f"获取WVP-Pro设备详情失败", device_id=device_id, exc_info=e)
            raise
    
    async def get_device_channels(self, device_id: str, page: int = 1, count: int = 100) -> List[WVPProChannel]:
        """获取设备通道列表"""
        try:
            # 确保已认证
            await self._ensure_authenticated()
            
            params = {
                'page': page,
                'count': count
            }
            
            response = await self._request('GET', f'api/device/query/devices/{device_id}/channels', params=params)
            
            channels = []
            # WVP返回格式: {"list": [...], "total": n}
            if 'list' in response:
                channel_list = response['list']
                for channel_data in channel_list:
                    channels.append(WVPProChannel(channel_data))
            
            logger.info(f"设备{device_id}获取到{len(channels)}个通道")
            return channels
            
        except Exception as e:
            logger.error("获取WVP-Pro设备通道失败", device_id=device_id, exc_info=e)
            return []
    
    async def start_play(self, device_id: str, channel_id: str) -> Optional[WVPProStreamInfo]:
        """开始播放视频流并返回流信息"""
        try:
            # 确保已认证
            await self._ensure_authenticated()
            
            # WVP使用GET方法启动播放
            response = await self._request('GET', f'api/play/start/{device_id}/{channel_id}')
            
            # WVP返回DeferredResult，200状态码表示请求成功发送
            logger.info(
                "WVP-Pro视频流启动请求已发送",
                device_id=device_id,
                channel_id=channel_id
            )
            
            # 等待一小段时间让流启动
            await asyncio.sleep(1)
            
            # 获取流信息
            stream_info = await self.get_play_url(device_id, channel_id)
            return stream_info
            
        except Exception as e:
            logger.error(
                "启动WVP-Pro视频流失败",
                device_id=device_id,
                channel_id=channel_id,
                exc_info=e
            )
            return None
    
    async def stop_play(self, device_id: str, channel_id: str) -> bool:
        """停止播放视频流"""
        try:
            # WVP使用GET方法停止播放
            response = await self._request('GET', f'api/play/stop/{device_id}/{channel_id}')
            
            logger.info(
                "WVP-Pro视频流停止请求已发送",
                device_id=device_id,
                channel_id=channel_id
            )
            return True
            
        except Exception as e:
            logger.error(
                "停止WVP-Pro视频流失败",
                device_id=device_id,
                channel_id=channel_id,
                exc_info=e
            )
            return False
    
    async def get_play_url(self, device_id: str, channel_id: str) -> Optional[WVPProStreamInfo]:
        """获取播放地址（不启动流）"""
        try:
            # 确保已认证
            await self._ensure_authenticated()
            
            response = await self._request('GET', f'api/play/{device_id}/{channel_id}')
            
            if 'data' in response:
                return WVPProStreamInfo(response['data'])
            elif response:
                # 有些版本直接返回流信息
                return WVPProStreamInfo(response)
            
            return None
            
        except Exception as e:
            logger.error(
                "获取WVP-Pro播放地址失败",
                device_id=device_id,
                channel_id=channel_id,
                exc_info=e
            )
            raise
    
    async def get_playback_url(
        self, 
        device_id: str, 
        channel_id: str, 
        start_time: datetime, 
        end_time: datetime
    ) -> Optional[str]:
        """获取录像回放地址"""
        try:
            data = {
                'deviceId': device_id,
                'channelId': channel_id,
                'startTime': start_time.strftime('%Y-%m-%d %H:%M:%S'),
                'endTime': end_time.strftime('%Y-%m-%d %H:%M:%S')
            }
            
            response = await self._request('POST', 'api/playback/start', json=data)
            
            if 'data' in response and 'url' in response['data']:
                playback_url = response['data']['url']
                logger.info(
                    "WVP-Pro录像回放地址获取成功",
                    device_id=device_id,
                    channel_id=channel_id,
                    url=playback_url
                )
                return playback_url
            
            return None
            
        except Exception as e:
            logger.error(
                "获取WVP-Pro录像回放地址失败",
                device_id=device_id,
                channel_id=channel_id,
                exc_info=e
            )
            raise
    
    async def ptz_control(
        self, 
        device_id: str, 
        channel_id: str, 
        command: str, 
        horizontal_speed: int = 50, 
        vertical_speed: int = 50, 
        zoom_speed: int = 50
    ) -> bool:
        """PTZ控制"""
        try:
            data = {
                'deviceId': device_id,
                'channelId': channel_id,
                'command': command,
                'horizonSpeed': horizontal_speed,
                'verticalSpeed': vertical_speed,
                'zoomSpeed': zoom_speed
            }
            
            response = await self._request('POST', 'api/ptz/control', json=data)
            
            success = response.get('code') == 0
            if success:
                logger.info(
                    "WVP-Pro PTZ控制成功",
                    device_id=device_id,
                    channel_id=channel_id,
                    command=command
                )
            
            return success
            
        except Exception as e:
            logger.error(
                "WVP-Pro PTZ控制失败",
                device_id=device_id,
                channel_id=channel_id,
                command=command,
                exc_info=e
            )
            raise
    
    async def test_connection(self) -> bool:
        """测试WVP-Pro连接"""
        try:
            await self._ensure_client()
            
            # 先测试基本连接
            response = await self._client.get("")
            if response.status_code != 200:
                return False
            
            # 尝试登录测试
            login_result = await self.login()
            return login_result is not None
            
        except Exception as e:
            logger.error("WVP-Pro连接测试失败", exc_info=e)
            return False
    
    async def login(self, username: str = "admin", password: str = "admin") -> Optional[Dict[str, Any]]:
        """登录WVP-Pro系统"""
        try:
            await self._ensure_client()
            
            # 密码需要32位MD5加密
            import hashlib
            md5_password = hashlib.md5(password.encode()).hexdigest()
            
            # 使用GET方法和查询参数
            params = {
                "username": username,
                "password": md5_password
            }
            
            response = await self._client.get(
                "api/user/login",
                params=params
            )
            
            if response.status_code == 200:
                data = response.json()
                # WVP返回的登录响应中，code=0表示成功
                if data.get("code") == 0:
                    logger.info("WVP-Pro登录成功")
                    
                    # 保存会话cookies
                    if response.cookies:
                        self._client.cookies.update(response.cookies)
                    
                    return data
                else:
                    logger.warning("WVP-Pro登录失败", response=data)
                    return None
            else:
                logger.error("WVP-Pro登录请求失败", status_code=response.status_code)
                return None
                
        except Exception as e:
            logger.error("WVP-Pro登录异常", exc_info=e)
            return None

    async def get_server_info(self) -> Dict[str, Any]:
        """获取服务器配置信息"""
        try:
            # 确保已认证
            await self._ensure_authenticated()
            
            response = await self._request('GET', 'api/server/config')
            if response.get('code') == 0:
                return response.get('data', {})
            else:
                raise Exception(f"获取服务器配置失败: {response.get('msg', '未知错误')}")
            
        except Exception as e:
            logger.error("获取WVP-Pro服务器信息失败", exc_info=e)
            raise
    
    async def get_media_servers(self) -> List[Dict[str, Any]]:
        """获取媒体服务器列表"""
        try:
            # 确保已认证
            await self._ensure_authenticated()
            
            response = await self._request('GET', 'api/server/media_server/list')
            
            if response.get('code') == 0 and response.get('data'):
                media_servers = response['data']
                logger.info(f"获取到{len(media_servers)}个媒体服务器")
                return media_servers
            else:
                logger.warning("未找到可用的媒体服务器")
                return []
                
        except Exception as e:
            logger.error("获取WVP-Pro媒体服务器列表失败", exc_info=e)
            return []


# 全局WVP-Pro客户端实例
_wvp_client: Optional[WVPProClient] = None


async def get_wvp_client() -> WVPProClient:
    """获取WVP-Pro客户端实例"""
    global _wvp_client
    
    if _wvp_client is None:
        _wvp_client = WVPProClient()
    
    return _wvp_client


async def close_wvp_client():
    """关闭WVP-Pro客户端"""
    global _wvp_client
    
    if _wvp_client:
        await _wvp_client.close()
        _wvp_client = None